﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using CookComputing.XmlRpc;
using System.Collections.Generic;
using System.ServiceModel;
using System.IO;
using System.Diagnostics;

namespace LiveWriterExample
{

    [ServiceContract]
    public interface IMetaWeblog
    {

        #region MetaWeblog API

        [XmlRpcMethod("metaWeblog.newPost")]
        [OperationContract(Action = "metaWeblog.newPost")]
        string AddPost(string blogid, string username, string password, Post post, bool publish);

        [XmlRpcMethod("metaWeblog.editPost")]
        bool UpdatePost(string postid, string username, string password, Post post, bool publish);

        [XmlRpcMethod("metaWeblog.getPost")]
        Post GetPost(string postid, string username, string password);

        [XmlRpcMethod("metaWeblog.getCategories")]
        CategoryInfo[] GetCategories(string blogid, string username, string password);

        [XmlRpcMethod("metaWeblog.getRecentPosts")]
        Post[] GetRecentPosts(string blogid, string username, string password, int numberOfPosts);

        [XmlRpcMethod("metaWeblog.newMediaObject")]
        MediaObjectInfo NewMediaObject(string blogid, string username, string password, MediaObject mediaObject);

        #endregion

        #region Blogger API

        [XmlRpcMethod("blogger.deletePost")]
        [return: XmlRpcReturnValue(Description = "Returns true.")]
        bool DeletePost(string key, string postid, string username, string password, bool publish);

        [XmlRpcMethod("blogger.getUsersBlogs")]
        BlogInfo[] GetUsersBlogs(string key, string username, string password);

        [XmlRpcMethod("blogger.getUserInfo")]
        UserInfo GetUserInfo(string key, string username, string password);

        #endregion

    }

    public class MetaWeblog : XmlRpcService, IMetaWeblog
    {

        #region Delete this code for real blog (used to persist blog)

        static MetaWeblog()
        {
            sUser = new UserInfo() { firstname = "John", lastname = "Smith", email = "john@smith.com", nickname = "Johnny", url = GetFullUrl("user", "john") };

            var blog = new BlogInfo() { blogid = "SampleBlog", blogName = "My Blog", url = GetFullUrl("blog", "myblog") };
            sBlogs.Add(blog.blogid, blog);
            var cats = new List<CategoryInfo>();
            sCategories.Add(blog.blogid, cats);
            cats.Add(new CategoryInfo() { categoryid = "MyCategory", title = "My category", description = "My category description", htmlUrl = GetFullUrl("blog", "SampleBlog", "MyCategory"), rssUrl = GetFullUrl("blog", "SampleBlog", "MyCategory", "rss") });
            cats.Add(new CategoryInfo() { categoryid = "AnotherCategory", title = "Another category", description = "Another category description", htmlUrl = GetFullUrl("blog", "SampleBlog", "AnotherCategory"), rssUrl = GetFullUrl("blog", "SampleBlog", "AnotherCategory", "rss") });
            sPosts.Add(blog.blogid, new Dictionary<string, Post>());

            blog = new BlogInfo() { blogid = "AnotherBlog", blogName = "Another Blog", url = GetFullUrl("blog", "anotherblog") };
            sBlogs.Add(blog.blogid, blog);
            cats = new List<CategoryInfo>();
            sCategories.Add(blog.blogid, cats);
            cats.Add(new CategoryInfo() { categoryid = "MyCategoryX", description = "My category X", htmlUrl = GetFullUrl("blog", "AnotherBlog", "MyCategory") });
            cats.Add(new CategoryInfo() { categoryid = "AnotherCategoryX", description = "Another category X", htmlUrl = GetFullUrl("blog", "AnotherBlog", "AnotherCategory") });
            sPosts.Add(blog.blogid, new Dictionary<string, Post>());
        }

        private static Dictionary<string, Dictionary<string, Post>> sPosts = new Dictionary<string, Dictionary<string, Post>>();
        private static Dictionary<string, List<CategoryInfo>> sCategories = new Dictionary<string, List<CategoryInfo>>();
        private static Dictionary<string, BlogInfo> sBlogs = new Dictionary<string, BlogInfo>();
        private static Dictionary<string, MediaObject> sMedia = new Dictionary<string, MediaObject>();
        private static UserInfo sUser;

        public override XmlRpcResponse Invoke(XmlRpcRequest request)
        {
            Debug.WriteLine(request.rawXml.OuterXml);
            return base.Invoke(request);
        }

        #endregion

        #region IMetaWeblog Members

        string IMetaWeblog.AddPost(string blogid, string username, string password, Post post, bool publish)
        {
            ValidateUser(username, password);

            // TODO: Implement your own logic
            var id = Guid.NewGuid().ToString();
            post.postid = id;
            post.permalink = GetFullUrl("blog", "SampleBlog", id);
            if (string.IsNullOrEmpty(post.wp_slug))
                post.wp_slug =  HttpUtility.UrlEncode("POST-" + post.title);
            sPosts[blogid].Add(id, post);

            return id;
        }

        bool IMetaWeblog.UpdatePost(string postid, string username, string password, Post post, bool publish)
        {
            ValidateUser(username, password);

            bool result = false;

            // TODO: Implement your own logic
            foreach (var blog in sPosts.Values)
            {
                if(blog.ContainsKey(postid))
                {
                    blog[postid] = post;
                    break;
                }
            }

            return result;
        }

        Post IMetaWeblog.GetPost(string postid, string username, string password)
        {
            ValidateUser(username, password);

            // TODO: Implement your own logic
            foreach (var blog in sPosts.Values)
            {
                if (blog.ContainsKey(postid))
                    return blog[postid];
            }

            throw new XmlRpcFaultException(2041, "Post not found");
        }

        CategoryInfo[] IMetaWeblog.GetCategories(string blogid, string username, string password)
        {
            ValidateUser(username, password);

            // TODO: Implement your own logic
            return sCategories[blogid].ToArray();
        }

        Post[] IMetaWeblog.GetRecentPosts(string blogid, string username, string password, int numberOfPosts)
        {
            ValidateUser(username, password);
           
            // TODO: Implement your own logic
            return sPosts[blogid].Values.ToArray();
        }

        MediaObjectInfo IMetaWeblog.NewMediaObject(string blogid, string username, string password, MediaObject mediaObject)
        {
            ValidateUser(username, password);

            // TODO: Implement your own logic
            MediaObjectInfo objectInfo = new MediaObjectInfo();
            objectInfo.url = GetFullUrl(blogid, blogid, "media", mediaObject.name);
            sMedia.Add(mediaObject.name, mediaObject);

            return objectInfo;
        }

        bool IMetaWeblog.DeletePost(string key, string postid, string username, string password, bool publish)
        {
            ValidateUser(username, password);
            
            // TODO: Implement your own logic
            foreach (var blog in sPosts.Values)
            {
                if (blog.ContainsKey(postid))
                {
                    blog.Remove(postid);
                    return true;
                }
            }

            return false;
        }

        BlogInfo[] IMetaWeblog.GetUsersBlogs(string key, string username, string password)
        {
            ValidateUser(username, password);
            
            // TODO: Implement your own logic
            // The blogid should be the same as the blogID from the RSD. Live Writer assumes that when the user adds the blog account, they will 
            // use the url to the actual blog they are adding and not to a more generic account. 
            // http://social.msdn.microsoft.com/Forums/en-US/wlwdev/thread/120e9562-1d02-485d-89a9-03364609e87c
            return sBlogs.Values.ToArray();
        }

        UserInfo IMetaWeblog.GetUserInfo(string key, string username, string password)
        {
            ValidateUser(username, password);

            // TODO: Implement your own logic
            return sUser;
        }

        #endregion

        #region Private Methods

        private void ValidateUser(string username, string password)
        {
            if (!IsUserValid(username, password)) throw new XmlRpcFaultException(2041, "User is not valid!");
        }

        private bool IsUserValid(string username, string password)
        {
            // TODO: Implement the logic to validate the user
            return true;
        }

        private static string GetFullUrl(params string[] paths)
        {
            return string.Format("http://{0}/{1}", HttpContext.Current.Request.Url.Authority, string.Join("/", paths));
        }

        #endregion

    }

}